const TYPE_REQUEST_CALL = "request-call"; //申请通话
const TYPE_RECEIVE_SUCCESS = "receive-success"; //成功接收通话请求
const TYPE_RECEIVE_REFUSED = "receive-refused"; //拒绝接收通话
const TYPE_RECEIVE_REFUSED_RESPONSE = "receive-refused"; //拒绝接收通话响应
const TYPE_REQUEST_CANCEL = "request-cancel"; //取消请求视频通话
const TYPE_REQUEST_CANCEL_RESPONSE = "request-cancel-response"; //对方取消视频通话响应
const TYPE_RECEIVE_CONNECTION = "receive-connection"; //接受视频通话连接
const TYPE_REQUEST_SUCCESS = "request-success"; //请求视频通话成功
const TYPE_REQUEST_CONN_HANDUP = "request-conn-handup"; //请求者挂断连接
const TYPE_RECEIVE_CONN_HANDUP = "receive-conn-handup"; //接收者挂断连接
const TYPE_CONN_HANDUP = "conn-handup"; //连接被挂断
const SIGNAL_TYPE_CANDIDATE = 'candidate'; //网络协商
const SIGNAL_TYPE_OFFER = 'offer'; //媒体协商
const SIGNAL_TYPE_ANSWER = 'answer'; //应答媒体协商

//获取元素 其实以下得看自身情况需求来做更改 但大体就是使用 window.location.search.substring(1)截取到凭借的参数 然后使用decodeURIComponent方法进行转译
//存储webview传递的参数
let parameters = new Map(); //跳转到该页面的参数信息
let requestEl = document.querySelector("#request");
let receiveEl = document.querySelector("#receive");
let handupBtn = document.querySelector(".handup"); //请求的挂断
let friendName = document.querySelector("#friendName"); //请求的对方姓名
let tips = document.querySelector(".tips"); //请求提示信息
let connectedEl = document.querySelector("#connected"); //通话中显示
let connHandupEl = document.querySelector("#conn_handup"); //通话中挂断按钮
let requestAvatarEL = document.querySelector("#req_img"); //申请用户头像
let requestNameEL = document.querySelector(".request_name"); //申请用户昵称
let receiveHandupEL = document.querySelector("#receive_handup"); //接收者挂断按钮
let receiveAcceptEL = document.querySelector("#receive_accept"); //接收者接收按钮
let overEL = document.querySelector("#over"); //通话接收提示
let handupAudio = document.querySelector("#handupAudio"); //挂断提示音
let receiveTipsEl = document.querySelector(".receive_tips"); //挂断提示信息
let callAudio = document.querySelector("#callAudio"); //通过背景铃声
let receiveImg = document.querySelector("#receiveImg"); //请求时请求者头像占位
let requestRemoteImg = document.querySelector("#requestRemoteImg"); //请求时接收者头像占位
let connTime = document.querySelector("#time"); //通话时长显示
let receiveAvatar = ""; //接收用户头像
let localVideo = null; //本地视频
let remoteVideo = null; //远端视频
let localStream = null; //本地视频流
let remoteStream = null; //对端视频流
let socket = null; //websocket
let isAccept = false; //是否是接收通话
let remoteId = '' //对端id，用于请求者
let fromId = '' //自己的id，用于请求者
let requestId = ''; //发起者id，用于接收者
let receiveId = ''; //接收者id，用于接收者
let connectedTime = 0; //通话总秒数
let timer = null; //统计通话时长计时器
// let wsUrl = 'wss://192.168.0.105:8009/socket/'; //websocket生产服务器地址
let wsUrl = 'ws://127.0.0.1:9999/socket/'; //websocket开发服务器地址
let pc = null; //视频流连接对象
let sessionId = null; //会话id

//通话时挂断
connHandupEl.addEventListener('click', () => {
	//连接挂断
	doConnHandup()
	overEL.style.visibility = 'visible'
	setTimeout(() => {
		//跳转到首页
		uni.reLaunch({
			url: "/pages/index/index"
		})
	}, 2000)
})
//uniapp事件
document.addEventListener('UniAppJSBridgeReady', function() {
	uni.getEnv(function(res) {
		console.log('当前环境：' + JSON.stringify(res));
	});
});
//发起者取消视频通话邀请
handupBtn.addEventListener("click", function() {
	let m = {
		fromId,
		remoteId,
		"msg": "取消请求通话"
	}
	let msg = {
		type: TYPE_REQUEST_CANCEL,
		data: m
	}
	//发送取消信息
	socket.send(JSON.stringify(msg))
	tips.innerHTML = "已取消";
	// 播放挂断声音
	callAudio.pause()
	handupAudio.play()
	setTimeout(() => {
		uni.reLaunch({
			url: "/pages/index/index"
		})
	}, 2000);
});
//接收者挂断
receiveHandupEL.addEventListener('click', function() {
	let m = {
		receiveId,
		requestId,
	}
	let msg = {
		type: TYPE_RECEIVE_REFUSED,
		data: m
	}
	//发送拒绝消息
	socket.send(JSON.stringify(msg));
	// 播放挂断声音
	receiveTipsEl.innerHTML = "已挂断视频"
	callAudio.pause()
	handupAudio.play()
	setTimeout(() => {
		uni.reLaunch({
			url: "/pages/index/index"
		})
	}, 2000);
});
//接收者接听
receiveAcceptEL.addEventListener('click', function() {
	doAccept()
});
//页面初始化
(function initPage() {
	//获取参数
	getUrlParam();
	//是否是接听
	isAccept = JSON.parse(parameters.get('isAccept'));
	if (isAccept) {
		//接收者
		requestEl.style.display = 'none';
		let requestAvatar = parameters.get('requestAvatar');
		let requestName = parameters.get('requestName');
		requestId = parameters.get("requestId");
		receiveId = parameters.get("receiveId");
		sessionId = parameters.get('sessionId');
		//用于发送candidate，此时交换身份
		fromId = receiveId;
		remoteId = requestId;
		receiveAvatar = parameters.get("receiveAvatar");
		requestAvatarEL.src = requestAvatar;
		requestNameEL.innerHTML = requestName;
		receiveImg.src = receiveAvatar;
	} else {
		//发起者
		receiveEl.style.display = 'none';
		let remoteAvatar = parameters.get('remoteAvatar');
		let remoteName = decodeURI(parameters.get('remoteName'));
		remoteId = parameters.get('remoteId');
		fromId = parameters.get('loginId');
		sessionId = parameters.get('sessionId');
		if (remoteName) {
			friendName.innerHTML = remoteName;
		}
		if (remoteAvatar) {
			requestRemoteImg.src = remoteAvatar;
		}
	}
	//初始化连接
	initWebSocket();
})();
//获取参数封装到map
function getUrlParam() {
	// 取得url中?后面的字符
	let query = window.location.search.substring(1);
	// 把参数按&拆分成数组
	let paramEntries = query.split("&");
	//封装参数到Map中
	paramEntries.forEach(item => {
		let kv = item.split('=');
		parameters.set(kv[0], kv[1]);
	})
}
//处理时长不够两位数补0
function prefixZero(num, n) {
	return (Array(n).join(0) + num).slice(-n);
}
//计时方法
function startConnetedTime() {
	let showSecond = 0 //显示的秒数
	let showMinute = 0 //显示的分钟
	timer = setInterval(() => {
		connectedTime++
		showMinute = Math.floor(connectedTime / 60)
		showSecond = connectedTime % 60
		if (showSecond < 10) {
			showSecond = prefixZero(showSecond, 2);
		}
		if (showMinute < 10) {
			showMinute = prefixZero(showMinute, 2);
		}
		connTime.innerText = showMinute + ":" + showSecond;
	}, 1000);
}
//打开摄像头
function openCamera() {
	return navigator.mediaDevices.getUserMedia({
		audio: true,
		video: {
			width: 720,
			height: 1280
		}
	})
}
//初始化信令服务器连接
function initWebSocket() {
	let token = localStorage.getItem("TOKEN");
	socket = new WebSocket(wsUrl + token);
}
//初始化socket事件
socket.onopen = function() {
	if (isAccept) {
		//处理请求响应
		doReceiveSuccess();
	} else {
		//请求者连接成功，发送通话请求
		doCall()
	}
}
//获得消息事件
socket.onmessage = function(msg) {
	let message = JSON.parse(msg.data)
	switch (message.type) {
		case TYPE_RECEIVE_REFUSED_RESPONSE:
			//拒绝了请求
			tips.innerHTML = message.msg
			// 播放挂断声音
			callAudio.pause()
			handupAudio.play()
			setTimeout(() => {
				uni.reLaunch({
					url: "/pages/index/index"
				})
			}, 2000);
			break;
		case TYPE_REQUEST_CANCEL_RESPONSE:
			//对方取消请求视频通话
			receiveTipsEl.innerHTML = message.msg
			// 播放挂断声音
			callAudio.pause()
			handupAudio.play()
			setTimeout(() => {
				uni.reLaunch({
					url: "/pages/index/index"
				})
			}, 2000);
			break;
		case TYPE_CONN_HANDUP:
			//连接挂断
			overEL.style.visibility = 'visible';
			handupAudio.play();
			setTimeout(() => {
				uni.reLaunch({
					url: "/pages/index/index"
				})
			}, 2000);
			break;
		case TYPE_REQUEST_SUCCESS:
			//请求视频通话成功
			doOffer()
			break;
		case SIGNAL_TYPE_OFFER:
			//处理offer
			handleOffer(message.data)
			break;
		case SIGNAL_TYPE_ANSWER:
			//处理answer
			handleAnswer(message.data)
			break;
		case SIGNAL_TYPE_CANDIDATE:
			//处理远端的网络信息
			handleRemoteCandidate(message.data)
			break;
	}
};
//关闭事件
socket.onclose = function() {
	alert("视频websocket关闭!")
	uni.reLaunch({
		url: "/pages/index/index"
	})
};
//发生了错误事件
socket.onerror = function() {
	uni.reLaunch({
		url: "/pages/index/index"
	})
}
//处理远端发来的网络协商数据
function handleRemoteCandidate(data) {
	let candidate = JSON.parse(data.msg)
	pc.addIceCandidate(candidate).catch(error => {
		console.log("网络协商失败！");
	})
}
//处理offer
async function handleOffer(data) {
	try {
		callAudio.pause();
		let stream = await toConnected(receiveEl)
		localStream = stream;
		localVideo.srcObject = stream;
	} catch (error) {
		console.log("接收者打开摄像头失败!");
	}
	if (pc == null) {
		createPeerConnection()
	}
	let sessionDescription = JSON.parse(data.msg)
	pc.setRemoteDescription(sessionDescription)
	doAnswer()
}
//处理answer
function handleAnswer(data) {
	let sessionDescription = JSON.parse(data.msg)
	pc.setRemoteDescription(sessionDescription)
}
//拨打视频
function doCall() {
	let m = {
		toId: parameters.get('remoteId'),
		fromId: parameters.get('loginId'),
		fromAvatar: parameters.get("loginAvatar"),
		fromName: parameters.get('loginName'),
		sessionId: sessionId
	}
	let msg = {
		type: TYPE_REQUEST_CALL,
		data: m
	}
	//发送通话请求
	socket.send(JSON.stringify(msg));
}
//成功收到请求处理
function doReceiveSuccess() {
	let m = {
		receiveId,
		requestId,
		msg: "收到通话请求"
	}
	let msg = {
		type: TYPE_RECEIVE_SUCCESS,
		data: m
	}
	//收到通话消息
	socket.send(JSON.stringify(msg));
}
//接受视频通话处理
function doAccept() {
	let m = {
		requestId,
		receiveId,
		msg: '接受视频通话'
	}
	let msg = {
		type: TYPE_RECEIVE_CONNECTION,
		data: m
	}
	socket.send(JSON.stringify(msg))
}
//准备创建offer
async function doOffer() {
	try {
		//停止铃声
		callAudio.pause();
		let stream = await toConnected(requestEl)
		localStream = stream;
		localVideo.srcObject = stream;
	} catch (error) {
		console.log("打开摄像头失败");
	}
	//创建RTCPeerConnection
	if (pc == null) {
		createPeerConnection();
	}
	pc.createOffer()
		.then(createOfferAndSendMessage)
		.catch(handleCreateOfferError);
}
//创建媒体协商信息
function createOfferAndSendMessage(sessionDescription) {
	//设置本地媒体支持
	pc.setLocalDescription(sessionDescription);
	let m = {
		remoteId,
		fromId,
		msg: JSON.stringify(sessionDescription)
	}
	let msg = {
		type: SIGNAL_TYPE_OFFER,
		data: m
	}
	socket.send(JSON.stringify(msg))
}
//显示通话界面
function toConnected(el) {
	//关闭请求中的界面显示
	el.style.display = "none";
	//打开通话中的界面
	connectedEl.style.display = "flex";
	//开始计时
	startConnetedTime()
	localVideo = document.querySelector("#localVideo");
	remoteVideo = document.querySelector("#remoteVideo");
	//打开摄像头
	return openCamera();
}
//准备创建answer
function doAnswer() {
	pc.createAnswer()
		.then(createAnswerAndSendMessage)
		.catch(handleCreateAnswerError);
}
//创建创建媒体协商应答并发送给对方
function createAnswerAndSendMessage(sessionDescription) {
	//设置本地媒体支持
	pc.setLocalDescription(sessionDescription);
	let m = {
		requestId,
		receiveId,
		msg: JSON.stringify(sessionDescription)
	}
	let msg = {
		type: SIGNAL_TYPE_ANSWER,
		data: m
	}
	socket.send(JSON.stringify(msg));
}
//视频通话中进行挂断
function doConnHandup() {
	clearInterval(timer)
	if (isAccept) {
		//是接收者挂断
		let m = {
			requestId,
			receiveId,
			msg: "接收者挂断连接",
			time: connectedTime,
			sessionId: sessionId
		}
		let msg = {
			type: TYPE_RECEIVE_CONN_HANDUP,
			data: m
		}
		socket.send(JSON.stringify(msg))
	} else {
		//请求者挂断
		let m = {
			fromId,
			remoteId,
			msg: "请求者挂断连接",
			time: connectedTime,
			sessionId: sessionId
		}
		let msg = {
			type: TYPE_REQUEST_CONN_HANDUP,
			data: m
		}
		socket.send(JSON.stringify(msg))
	}
}

//创建媒体协商应答失败处理
function handleCreateAnswerError() {
	console.log("创建Answer失败");
}

//创建媒体协商信息失败处理
function handleCreateOfferError() {
	console.log("创建offer失败");
}
//创建PeerConnection
function createPeerConnection() {
	//本地连接直接传入null,公网连接需要传递参数
	pc = new RTCPeerConnection(null)
	//绑定事件
	//发送网络协商信息
	pc.onicecandidate = handleIceCandidate
	//绑定对端传来的stream
	pc.ontrack = handleRemoteStreamAdd
	//将本地stream添加到RTCPeerConnection
	localStream.getTracks().forEach((track) => {
		pc.addTrack(track, localStream)
	})
}
//网络协商信息
function handleIceCandidate(event) {
	if (event.candidate) {
		let m = {
			remoteId,
			fromId,
			msg: JSON.stringify(event.candidate)
		}
		let msg = {
			type: SIGNAL_TYPE_CANDIDATE,
			data: m
		}
		socket.send(JSON.stringify(msg))
	}
}
//添加视频流
function handleRemoteStreamAdd(event) {
	remoteStream = event.streams[0]
	remoteVideo.srcObject = remoteStream
}
